home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / rpc / rpcServer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-19  |  41.3 KB  |  1,428 lines

  1. /*
  2.  * rpcServer.c --
  3.  *
  4.  *      This is the top level code for an RPC server process, plus the
  5.  *      server-side dispatch routine with which the server process must
  6.  *      synchronize.  sA server process does some initialization and then
  7.  *      goes into a service loop receiving request messages and invoking
  8.  *      service stubs.  This file also has utilities for sending replies
  9.  *      and acks.
  10.  *
  11.  * Copyright (C) 1985 Regents of the University of California
  12.  * All rights reserved.
  13.  */
  14.  
  15. #ifndef lint
  16. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/rpc/rpcServer.c,v 9.26 92/12/13 18:21:37 mgbaker Exp $ SPRITE (Berkeley)";
  17. #endif /* not lint */
  18.  
  19.  
  20. #include <sprite.h>
  21. #include <stdio.h>
  22. #include <bstring.h>
  23. #include <rpc.h>
  24. #include <rpcInt.h>
  25. #include <rpcServer.h>
  26. #include <rpcTrace.h>
  27. #include <rpcHistogram.h>
  28. #include <net.h>
  29. #include <proc.h>
  30. #include <dbg.h>
  31. #include <stdlib.h>
  32. #include <recov.h>
  33.  
  34.  
  35. /*
  36.  * An on/off switch for the service side of the RPC system.  Hosts do not
  37.  * initially respond to RPC requests so they can configure themselves
  38.  * as needed at boot time.  This means we are dependent on a user program
  39.  * to execute and turn on this flag.
  40.  */
  41. Boolean rpcServiceEnabled = FALSE;
  42.  
  43. /*
  44.  * The server state table.  It has a maximum size which constrains the
  45.  * number of server processes that can be created.  The number of free
  46.  * servers is maintained, as well as the total number of created servers.
  47.  */
  48. RpcServerState **rpcServerPtrPtr = (RpcServerState **)NIL;
  49. int        rpcAbsoluteMaxServers = 70;
  50. int        rpcMaxServers = 50;
  51. int        rpcNumServers = 0;
  52.  
  53. /*
  54.  * rpcMaxServerAge is the number of times the Rpc_Daemon will send
  55.  * a probe message to a client (without response) before forcibly
  56.  * reclaiming the server process for use by other clients.  A probe
  57.  * message gets sent each time the daemon wakes up and finds the
  58.  * server process still idle awaiting a new request from the client.
  59.  */
  60. int rpcMaxServerAge = 10;    /* For testing set to 1. Was 10. */
  61.  
  62. /*
  63.  * A histogram is kept of service time.  This is available to user
  64.  * programs via the Sys_Stats SYS_RPC_SERVER_HIST command.  The on/off
  65.  * flags is settable via Fs_Command FS_SET_RPC_SERVER_HIST
  66.  */
  67. Rpc_Histogram *rpcServiceTime[RPC_LAST_COMMAND+1];
  68. Boolean rpcServiceTiming = FALSE;
  69.  
  70. /*
  71.  * A raw count of the number of service calls.
  72.  */
  73. int rpcServiceCount[RPC_LAST_COMMAND+1];
  74.  
  75. /*
  76.  * Buffers for sending negative acknowledgements.
  77.  */
  78. NackData    rpcNack;
  79. /*
  80.  * Whether or not to send negative acknowledgements.
  81.  */
  82. Boolean        rpcSendNegAcks = FALSE;
  83. /*
  84.  * Number of nack buffers in system.
  85.  */
  86. int    rpc_NumNackBuffers = 4;
  87. /*
  88.  * To tell if we've already initialized the correct number of nack buffers
  89.  * when the rpc system is turned on.  This variable equals the number of
  90.  * nack buffers last initialized.
  91.  */
  92. int    oldNumNackBuffers = 0;
  93.  
  94.  
  95. /*
  96.  * For tracing the behavior of the rpc servers.
  97.  */
  98. typedef struct    RpcServerStateInfo {
  99.     int        index;
  100.     int        clientID;
  101.     int        channel;
  102.     int        state;
  103.     int        num;
  104.     Timer_Ticks    time;
  105. } RpcServerStateInfo;
  106.  
  107. typedef    struct    RpcServerTraces {
  108.     RpcServerStateInfo    *traces;
  109.     int            traceIndex;
  110.     Boolean        okay;
  111.     Boolean        error;
  112.     Sync_Semaphore    mutex;
  113. } RpcServerTraces;
  114.  
  115. RpcServerTraces    rpcServerTraces = {(RpcServerStateInfo *) NIL, 0,  FALSE,
  116.                 FALSE, Sync_SemInitStatic("rpcServerTraces")};
  117.  
  118. /*
  119.  * Try 1 Meg of traces.
  120.  */
  121. #define RPC_NUM_TRACES (0x100000 / sizeof (RpcServerStateInfo))
  122.  
  123. static void NegAckFunc _ARGS_((ClientData clientData, Proc_CallInfo *callInfoPtr));
  124.  
  125.  
  126.  
  127.  
  128. /*
  129.  *----------------------------------------------------------------------
  130.  *
  131.  * Rpc_Server --
  132.  *
  133.  *      The top level procedure of an RPC server process.  This
  134.  *      synchronizes with RpcServerDispatch while it waits for new
  135.  *      requests to service.  It assumes that its buffers contain a new
  136.  *      request when its SRV_BUSY state bit is set.  It clears this bit
  137.  *      and sets the SRV_WAITING bit after it completes the service
  138.  *      procedure and returns a reply to the client.
  139.  *
  140.  * Results:
  141.  *    This procedure never returns.
  142.  *
  143.  * Side effects:
  144.  *    The server process attaches itself to a slot in the
  145.  *    table of server states.  Some statistics are taken at this level.
  146.  *
  147.  *----------------------------------------------------------------------
  148.  */
  149. void
  150. Rpc_Server()
  151. {
  152.     register RpcServerState *srvPtr;    /* This server's state */
  153.     register RpcHdr *rpcHdrPtr;        /* Its request message header */
  154.     register int command;        /* Identifies the service procedure */
  155.     register ReturnStatus error;    /* Return error code */
  156.     Rpc_Storage storage;        /* Specifies storage of request and
  157.                      * reply buffers passed into the stubs*/
  158.     Proc_ControlBlock *procPtr;        /* our process information */
  159.  
  160.     procPtr = Proc_GetCurrentProc();
  161.  
  162.     srvPtr = RpcServerInstall();
  163.     if (srvPtr == (RpcServerState *)NIL) {
  164.     printf("RPC server can't install itself.\n");
  165.     Proc_Exit((int) RPC_INTERNAL_ERROR);
  166.     }
  167.     error = SUCCESS;
  168.     for ( ; ; ) {
  169.     int    oldState;
  170.     /*
  171.      * Synchronize with RpcServerDispatch and await a request message.
  172.      * Change our state to indicate that we are ready for input.
  173.      */
  174.     MASTER_LOCK(&srvPtr->mutex);
  175.     oldState = srvPtr->state;
  176.     srvPtr->state &= ~(SRV_BUSY|SRV_STUCK);
  177.     srvPtr->state |= SRV_WAITING;
  178.     if (error == RPC_NO_REPLY) {
  179.         srvPtr->state |= SRV_NO_REPLY;
  180.     }
  181.     while ((srvPtr->state & SRV_BUSY) == 0) {
  182.         Sync_MasterWait(&srvPtr->waitCondition,
  183.                 &srvPtr->mutex, TRUE);
  184.         if (sys_ShuttingDown) {
  185.         srvPtr->state = SRV_NOTREADY;
  186.         MASTER_UNLOCK(&srvPtr->mutex);
  187.         Proc_Exit(0);
  188.         }
  189.     }
  190.     srvPtr->state &= ~SRV_NO_REPLY;
  191.     MASTER_UNLOCK(&srvPtr->mutex);
  192.  
  193.     /*
  194.      * At this point there is unsynchronized access to
  195.      * the server state.  We are marked BUSY, however, and
  196.      * RpcServerDispatch knows this and doesn't muck accordingly.
  197.      */
  198.     rpcHdrPtr = &srvPtr->requestRpcHdr;
  199. #ifdef NOTDEF
  200.     if (Recov_HoldForRecovery(rpcHdrPtr->clientID, rpcHdrPtr->command)) {
  201.         /* This will send a NegAck. */
  202. printf("Trying to send a neg ack to %d for command %d\n", rpcHdrPtr->clientID,
  203. rpcHdrPtr->command);
  204.         RpcServerDispatch((RpcServerState *) NIL, rpcHdrPtr);
  205.         MASTER_LOCK(&srvPtr->mutex);
  206.         srvPtr->state = oldState;
  207.         MASTER_UNLOCK(&srvPtr->mutex);
  208.         continue;
  209.     }
  210. #endif /* NOTDEF */
  211.  
  212.     /*
  213.      * Free up our previous reply.  The freeReplyProc is set by the
  214.      * call to Rpc_Reply.
  215.      */
  216. #ifndef lint
  217.     /* Won't lint due to cast of function ptr to address. */
  218.     if ((Address)srvPtr->freeReplyProc != (Address)NIL) {
  219.         (void)(*srvPtr->freeReplyProc)(srvPtr->freeReplyData);
  220.         srvPtr->freeReplyProc = (int (*)())NIL;
  221.     }
  222. #endif /* lint */
  223.  
  224. #ifdef TIMESTAMP
  225.     RPC_TRACE(rpcHdrPtr, RPC_SERVER_A, " input");
  226. #endif /* TIMESTAMP */
  227.     /*
  228.      * Monitor message traffic to keep track of other hosts.  This call
  229.      * has a side effect of blocking the server process while any
  230.      * crash recovery call-backs are in progress.
  231.      */
  232. #ifndef NO_RECOVERY
  233.     Recov_HostAlive(srvPtr->clientID, rpcHdrPtr->bootID,
  234.             FALSE, (Boolean) (rpcHdrPtr->flags & RPC_NOT_ACTIVE),
  235.             FALSE);
  236. #endif
  237.     /*
  238.      * Before branching to the service procedure we check that the
  239.      * server side of RPC is on, and that the RPC number is good.
  240.      * The "disabled service" return code is understood by other
  241.      * hosts to mean that we are still alive, but are not yet
  242.      * ready to be a server - ie. we are still checking disks etc.
  243.      */
  244.     command = rpcHdrPtr->command;
  245.     if (!rpcServiceEnabled) {
  246.         /*
  247.          * Silently ignore broadcast requests.  If we return an error
  248.          * we'll cause the sender to stop pre-maturely.  Otherwise
  249.          * return an indication that our service is not yet ready.
  250.          */
  251.         if (rpcHdrPtr->serverID == RPC_BROADCAST_SERVER_ID) {
  252.         error = RPC_NO_REPLY;
  253.         } else {
  254.         error = RPC_SERVICE_DISABLED;
  255.         }
  256.     } else if (command <= 0 || command > RPC_LAST_COMMAND) {
  257.         error = RPC_INVALID_RPC;
  258.     } else {
  259.         Time histTime;
  260.  
  261.         rpcServiceCount[command]++;
  262.  
  263.         RPC_SERVICE_TIMING_START(command, &histTime);
  264.  
  265.         storage.requestParamPtr    = srvPtr->request.paramBuffer.bufAddr;
  266.         storage.requestParamSize    = srvPtr->actualParamSize;
  267.         storage.requestDataPtr    = srvPtr->request.dataBuffer.bufAddr;
  268.         storage.requestDataSize    = srvPtr->actualDataSize;
  269.         storage.replyParamPtr    = (Address)NIL;
  270.         storage.replyParamSize    = 0;
  271.         storage.replyDataPtr    = (Address)NIL;
  272.         storage.replyDataSize    = 0;
  273.         error = (rpcService[command].serviceProc)((ClientData)srvPtr,
  274.                   srvPtr->clientID, command, &storage);
  275.         RPC_SERVICE_TIMING_END(command, &histTime);
  276.     }
  277.     /*
  278.      * Return an error reply for the stubs.  Note: We could send all
  279.      * replies if the stubs were all changed...
  280.      */
  281.     if (error != SUCCESS && error != RPC_NO_REPLY) {
  282.         Rpc_ErrorReply((ClientData)srvPtr, error);
  283.     }
  284. #ifdef TIMESTAMP
  285.     RPC_TRACE(rpcHdrPtr, RPC_SERVER_OUT, " done");
  286. #endif /* TIMESTAMP */
  287.     }
  288. }
  289.  
  290. /*
  291.  *----------------------------------------------------------------------
  292.  *
  293.  * RpcReclaimServers() --
  294.  *
  295.  *    Spin through the pool of server processes looking for ones to
  296.  *    reclaimed.  A server is eligible for reclaimation if it has been
  297.  *    idle (no new requests from its client) for a given number of
  298.  *    passes over the pool of servers.  It is reclaimed by getting
  299.  *    an explicit acknowledgment from the client and then marking
  300.  *    the server as SRV_FREE.
  301.  *
  302.  *    WARNING: it is possible for this routine to be called very often,
  303.  *    with the daemon being woken up by DAEMON_POKED rather than the
  304.  *    DAEMON_TIMEOUT.  Potentially, this might not give clients enough
  305.  *    time to do an RPC.  This doesn't seem to happen, but we should
  306.  *    change this routine at some point to make sure it can't happen.
  307.  *
  308.  *
  309.  * Results:
  310.  *    None.
  311.  *
  312.  * Side effects:
  313.  *    Age servers, send probes to idle clients, recycle reclaimied servers.
  314.  *    If a client crashes, this routine detects it and reclaims the
  315.  *    server process associated with it and marks the client dead.
  316.  *
  317.  *----------------------------------------------------------------------
  318.  */
  319. ENTRY void
  320. RpcReclaimServers(serversMaxed)
  321.     Boolean serversMaxed;    /* TRUE if the maximum number of servers
  322.                  * have been created.  We reclaim more
  323.                  * quickly if this is set. */
  324. {
  325.     int srvIndex;
  326.     register RpcServerState *srvPtr;
  327.     int (*procPtr)();
  328.     ClientData data = (ClientData) NULL;
  329.  
  330.     for (srvIndex=0 ; srvIndex < rpcNumServers ; srvIndex++) {
  331.     srvPtr = rpcServerPtrPtr[srvIndex];
  332.  
  333.     MASTER_LOCK(&srvPtr->mutex);
  334.  
  335.  
  336.     procPtr = (int (*)())NIL;
  337.     if ((srvPtr->clientID >= 0) &&
  338.         (srvPtr->state & SRV_WAITING)) {
  339.          if (srvPtr->state & SRV_NO_REPLY) {
  340.         /*
  341.          * Reclaim right away if the server process is tied
  342.          * up not replying to a broadcast request.
  343.          */
  344.         procPtr = srvPtr->freeReplyProc;
  345.         data = srvPtr->freeReplyData;
  346.         srvPtr->freeReplyProc = (int (*)())NIL;
  347.         srvPtr->freeReplyData = (ClientData)NIL;
  348.         srvPtr->state = SRV_FREE|SRV_NO_REPLY;
  349.         RpcAddServerTrace(srvPtr, (RpcHdr *) NIL, FALSE, 5);
  350.         } else if ((srvPtr->state & SRV_AGING) == 0) {
  351.         /*
  352.          * This is the first pass over the server process that
  353.          * has found it idle.  Start it aging.
  354.          */
  355.         srvPtr->state |= SRV_AGING;
  356.         RpcAddServerTrace(srvPtr, (RpcHdr *) NIL, FALSE, 6);
  357.         srvPtr->age = 1;
  358.         if (serversMaxed) {
  359.             RpcProbe(srvPtr);
  360.         }
  361.         } else {
  362.         /*
  363.          * This process has aged since the last time we looked, maybe
  364.          * sleepTime ago.  We resend to the client with the
  365.          * close flag and continue on.  If RpcServerDispatch gets
  366.          * a reply from the client closing its connection it will
  367.          * mark the server process SRV_FREE.  If we continue to
  368.          * send probes with no reply, we give up after N tries
  369.          * and free up the server.  It is possible that the client
  370.          * has re-allocated its channel, in which case it drops
  371.          * our probes on the floor, or that it has crashed.
  372.          */
  373.         srvPtr->age++;
  374.         if (srvPtr->age >= rpcMaxServerAge) {
  375.             procPtr = srvPtr->freeReplyProc;
  376.             data = srvPtr->freeReplyData;
  377.             srvPtr->freeReplyProc = (int (*)())NIL;
  378.             srvPtr->freeReplyData = (ClientData)NIL;
  379.             rpcSrvStat.reclaims++;
  380.             srvPtr->state = SRV_FREE;
  381.             RpcAddServerTrace(srvPtr, (RpcHdr *) NIL, FALSE, 7);
  382. #ifdef notdef
  383.         } else if (srvPtr->clientID == rpc_SpriteID) {
  384.             printf("Warning: Reclaiming from myself.\n");
  385.             srvPtr->state = SRV_FREE;
  386.             RpcAddServerTrace(srvPtr, (RpcHdr *) NIL, FALSE, 8);
  387. #endif
  388.         } else {
  389.             /*
  390.              * Poke at the client to get a response.
  391.              */
  392.             RpcProbe(srvPtr);
  393.         }
  394.         }
  395.     } else if ((srvPtr->state & SRV_FREE) &&
  396.            (srvPtr->freeReplyProc != (int (*)())NIL)) {
  397.         /*
  398.          * Tidy up after an explicit acknowledgment from a client.
  399.          * This can't be done at interrupt time by ServerDispatch.
  400.          */
  401.         procPtr = srvPtr->freeReplyProc;
  402.         data = srvPtr->freeReplyData;
  403.         srvPtr->freeReplyProc = (int (*)())NIL;
  404.         srvPtr->freeReplyData = (ClientData)NIL;
  405.     }
  406.     MASTER_UNLOCK(&srvPtr->mutex);
  407.     /*
  408.      * Do the call-back to free up resources associated with the last RPC.
  409.      */
  410.     if (procPtr != (int (*)())NIL) {
  411.         (void)(*procPtr)(data);
  412.     }
  413.     }
  414. }
  415.  
  416.  
  417.  
  418. /*
  419.  *----------------------------------------------------------------------
  420.  *
  421.  * NegAckFunc --
  422.  *
  423.  *    Call-back to send a negative acknowledgement so that we won't be at
  424.  *    interrupt level while doing this.
  425.  *
  426.  * Results:
  427.  *    None.
  428.  *
  429.  * Side effects:
  430.  *    A negative ack is output.
  431.  *
  432.  *----------------------------------------------------------------------
  433.  */
  434. static void
  435. NegAckFunc(clientData, callInfoPtr)
  436.     ClientData        clientData;
  437.     Proc_CallInfo    *callInfoPtr;
  438. {
  439.     int            i;
  440.  
  441.     MASTER_LOCK(&(rpcNack.mutex));
  442.     /*
  443.      * We may handle more than one request here.
  444.      */
  445.     for (i = 0; i < rpc_NumNackBuffers; i++) {
  446.     if (rpcNack.hdrState[i] == RPC_NACK_WAITING) {
  447.         rpcNack.hdrState[i] = RPC_NACK_XMITTING;
  448.         rpcNack.rpcHdrArray[i].flags = RPC_NACK | RPC_ACK;
  449.         /*
  450.          * Already did an RpcSrvInitHdr from incoming rpcHdrPtr to our
  451.          * outgoing * buffer in RpcServerDispatch.
  452.          */
  453.         /*
  454.          * This should be okay to do under a masterlock since RpcAck
  455.          * also calls it and it's under a masterlock.
  456.          */
  457.         RpcAddServerTrace((RpcServerState *) NIL, &(rpcNack.rpcHdrArray[i]),
  458.             TRUE, 19);
  459.         rpcSrvStat.nacks++;
  460.         /*
  461.          * Because we pass it the mutex, it will return only when the xmit
  462.          * is done.
  463.          */
  464.         (void) RpcOutput(rpcNack.rpcHdrArray[i].clientID,
  465.             &(rpcNack.rpcHdrArray[i]), &(rpcNack.bufferSet[i]),
  466.             (RpcBufferSet *) NIL, 0,
  467.             (Sync_Semaphore *) &(rpcNack.mutex));
  468.         rpcNack.hdrState[i] = RPC_NACK_FREE;
  469.         rpcNack.numFree++;
  470.     }
  471.     }
  472.     MASTER_UNLOCK(&(rpcNack.mutex));
  473.     return;
  474. }
  475.  
  476.  
  477. /*
  478.  *----------------------------------------------------------------------
  479.  *
  480.  * RpcServerDispatch --
  481.  *
  482.  *      Handle a message sent to a server process.  The client sends (and
  483.  *      re-sends) request messages to the server host.  This routine
  484.  *      handles incoming message accoring to the RPC protocol.  Only new
  485.  *      request messages are passed to the server process.  All other
  486.  *      messages are handled in this routine.
  487.  *
  488.  * Results:
  489.  *    None.
  490.  *
  491.  * Side effects:
  492.  *      The side effects depend on the type of message received.  New
  493.  *      requests are passed off to server processes, client acknowledgments
  494.  *      and retries are processed and discarded.  Unneeded messages are
  495.  *    discarded by returning without copying the message out of the
  496.  *    network buffers.
  497.  *
  498.  *----------------------------------------------------------------------
  499.  */
  500. ENTRY void
  501. RpcServerDispatch(srvPtr, rpcHdrPtr)
  502.     register RpcServerState *srvPtr;    /* The state of the server process */
  503.     register RpcHdr *rpcHdrPtr;        /* The header of the packet as it sits
  504.                      * in the hardware buffers */
  505. {
  506.     register int size;        /* The amount of the data in the message */
  507.     int        i;
  508.     int        foundSpot;    /* Neg ack buf to use. */
  509.     int        alreadyFunc;    /* What buf neg ack function is dealing with. */
  510.  
  511.  
  512.     /*
  513.      * If the server pointer is NIL, this means no server could be allocated
  514.      * and a negative acknowledgement must be issued.
  515.      */
  516.     if (srvPtr == (RpcServerState *) NIL) {
  517.     if (rpcHdrPtr->clientID == rpc_SpriteID) {
  518.         /*
  519.          * Can't nack myself since the network module turns around and
  520.          * reroutes the message and we get deadlock.  Drop the neg ack.
  521.          */
  522.         printf("Can't nack to myself!\n");
  523.         rpcSrvStat.selfNacks++;
  524.         return;
  525.     }
  526.     MASTER_LOCK(&(rpcNack.mutex));
  527.     if (rpc_NumNackBuffers - rpcNack.numFree >
  528.         rpcSrvStat.mostNackBuffers) {
  529.         rpcSrvStat.mostNackBuffers = rpc_NumNackBuffers - rpcNack.numFree;
  530.     }
  531.     if (rpcNack.numFree <= 0) {
  532.         /* Drop the negative ack. */
  533.         MASTER_UNLOCK(&(rpcNack.mutex));
  534.         return;
  535.     }
  536.     /*
  537.      * Copy rpc header info to safe place that won't be freed when
  538.      * we return.
  539.      */
  540.     alreadyFunc = -1;
  541.     foundSpot = -1;
  542.     for (i = 0; i < rpc_NumNackBuffers; i++) {
  543.         /*
  544.          * If we haven't already found a buffer to use and this one is
  545.          * free, use it.
  546.          */
  547.         if (foundSpot == -1 && rpcNack.hdrState[i] == RPC_NACK_FREE) {
  548.         rpcNack.numFree--;
  549.         rpcNack.hdrState[i] = RPC_NACK_WAITING;
  550.         foundSpot = i;
  551.         RpcSrvInitHdr((RpcServerState *) NIL, 
  552.                 &(rpcNack.rpcHdrArray[i]), rpcHdrPtr);
  553.         /*
  554.          * If we've found evidence that there's already a CallFunc for
  555.          * the NegAckFunc, then record the first buffer it will be dealing
  556.          * with next.
  557.          */
  558.         } else if (alreadyFunc == -1 &&
  559.             rpcNack.hdrState[i] == RPC_NACK_WAITING) {
  560.         alreadyFunc = i;
  561.         }
  562.     }
  563.     /*
  564.      * If we've found a buffer and either there's no CallFunc or else it
  565.      * is already past the buffer we've grabbed, then start another
  566.      * CallFunc.
  567.      */
  568.     if (foundSpot != -1 &&
  569.         (alreadyFunc == -1 || alreadyFunc >= foundSpot)) {
  570.         MASTER_UNLOCK(&(rpcNack.mutex));
  571.         Proc_CallFunc(NegAckFunc, (ClientData) NIL, 0);
  572.         return;
  573.     /*
  574.      * Otherwise if we've found a buffer, there's already a CallFunc.
  575.      */
  576.     } else if (foundSpot != -1) {
  577.         MASTER_UNLOCK(&(rpcNack.mutex));
  578.         return;
  579.     }
  580.     MASTER_UNLOCK(&(rpcNack.mutex));
  581.     /*
  582.      * If we haven't found a free buffer, something is wrong.
  583.      */
  584.     panic("RpcServerDispatch: couldn't find free rpcHdr.\n");
  585.     }
  586.  
  587.     /*
  588.      * Acquire the server's mutex for multiprocessor synchronization.  We
  589.      * synchronize with each server process with a mutex that is part of
  590.      * the server's state.
  591.      */
  592.     MASTER_LOCK(&srvPtr->mutex);
  593.     
  594. #ifdef TIMESTAMP
  595.     RPC_TRACE(rpcHdrPtr, RPC_SERVER_a, " server");
  596. #endif /* TIMESTAMP */
  597.     /*
  598.      * Reset aging servers.  This information is maintained by Rpc_Deamon.
  599.      * The reception of a message for the server makes it no longer idle.
  600.      */
  601.     srvPtr->state &= ~SRV_AGING;
  602.     srvPtr->age = 0;
  603.  
  604.     /*
  605.      * If the RPC sequence number is different than the one saved in the
  606.      * server's state then this request signals a new RPC.  We use this as
  607.      * an implicit acknowledgment of the last reply the server sent.  The
  608.      * last transaction ID is saved in the rpc header of our last reply
  609.      * message.
  610.      */
  611.     if (rpcHdrPtr->ID != srvPtr->ID) {
  612.  
  613.     rpcSrvStat.requests++;
  614.     if (srvPtr->state & SRV_WAITING) {
  615.         /*
  616.          * The server has computed a result already so we treat this
  617.          * new request as an implicit acknowledgment of the reply the
  618.          * server sent.  The server process will clean up the previous
  619.          * reply before it starts computing the new reply.
  620.          */
  621.         rpcSrvStat.impAcks++;
  622.         srvPtr->state &= ~SRV_WAITING;
  623.     }
  624.  
  625.     if (srvPtr->state & SRV_FRAGMENT) {
  626.         /*
  627.          * The last send by the client was fragmented but was aborted
  628.          * before we got all the fragments.  Reset the fragment
  629.          * reasembly process.
  630.          */
  631.         rpcSrvStat.fragAborts++;
  632.         srvPtr->state &= ~SRV_FRAGMENT;
  633.         srvPtr->fragsReceived = 0;
  634.     }
  635.  
  636.     if (srvPtr->state & SRV_BUSY) {
  637.         /*
  638.          * The client has abandoned the RPC and started on a new one.
  639.          * This server process may be stuck on some lock, or the
  640.          * client may just be in error.  We mark the server process
  641.          * as STUCK so subsequent requests will not use this server,
  642.          * and the server process will unmark itself when it completes
  643.          * what ever its working on.
  644.          */
  645.         rpcSrvStat.serverBusy++;
  646.         srvPtr->state |= SRV_STUCK;
  647.         goto unlock;
  648.     }
  649.     /*
  650.      * (There should be no bits set in the server's state word.)
  651.      *
  652.      * Update the server's idea of the current transaction.
  653.      */
  654.     srvPtr->ID = rpcHdrPtr->ID;
  655.     /*
  656.      * Reset the true sizes of the two data areas in the arriving message.
  657.      */
  658.     srvPtr->actualDataSize = 0;
  659.     srvPtr->actualParamSize = 0;
  660.     /*
  661.      * Reset our knowledge of what fragments our client has.
  662.      */
  663.     srvPtr->fragsDelivered = 0;
  664.     /*
  665.      * Copy the message from the network's buffers into those of
  666.      * the server process.
  667.      */
  668.     RpcScatter(rpcHdrPtr, &srvPtr->request);
  669.  
  670.     /*
  671.      * Note the actual size of the input information.
  672.      */
  673.     size = rpcHdrPtr->paramSize + rpcHdrPtr->paramOffset;
  674.     if (srvPtr->actualParamSize < size) {
  675.         srvPtr->actualParamSize = size;
  676.     }
  677.     size = rpcHdrPtr->dataSize + rpcHdrPtr->dataOffset;
  678.     if (srvPtr->actualDataSize < size) {
  679.         srvPtr->actualDataSize = size;
  680.     }
  681.     if (rpcHdrPtr->numFrags == 0) {
  682.         /*
  683.          * The message is complete, ie. not fragmented.
  684.          * Return ack if needed and notify the server process.
  685.          */
  686.         srvPtr->fragsReceived = 0;
  687.         if (rpcHdrPtr->flags & RPC_PLSACK) {
  688.         rpcSrvStat.handoffAcks++;
  689.         RpcAck(srvPtr, 0);
  690.         }
  691.         srvPtr->state = SRV_BUSY;
  692. #ifdef WOULD_LIKE
  693.         RpcAddServerTrace(srvPtr, (RpcHdr *) NIL, FALSE, 2);
  694. #endif WOULD_LIKE
  695.         rpcSrvStat.handoffs++;
  696.         Sync_MasterBroadcast(&srvPtr->waitCondition);
  697.     } else {
  698.         /*
  699.          * The new arrival is only a fragment.
  700.          * Initiate fragment reassembly.  The server process is not
  701.          * notified until the request message is complete.
  702.          */
  703.         rpcSrvStat.fragMsgs++;
  704.         srvPtr->state = SRV_FRAGMENT;
  705.         srvPtr->fragsReceived = rpcHdrPtr->fragMask;
  706.         if (rpcHdrPtr->flags & RPC_PLSACK) {
  707.         rpcSrvStat.fragAcks++;
  708.         RpcAck(srvPtr, RPC_LASTFRAG);
  709.         }
  710.     }
  711. #ifdef TIMESTAMP
  712.     RPC_TRACE(rpcHdrPtr, RPC_SERVER_b, "handoff");
  713. #endif /* TIMESTAMP */
  714.     } else {
  715.     /*
  716.      * This is a message concerning a current RPC.
  717.      */
  718.     if (srvPtr->state & SRV_NO_REPLY) {
  719.         /*
  720.          * The current RPC was a broadcast which we do not want
  721.          * to reply to.  Keep ourselves free - the allocation routine
  722.          * has cleared that state bit.
  723.          */
  724.         srvPtr->state |= SRV_FREE;
  725.         RpcAddServerTrace(srvPtr, (RpcHdr *) NIL, FALSE, 9);
  726.         rpcSrvStat.discards++;
  727.     } else if (rpcHdrPtr->flags & RPC_ACK) {
  728.         if (rpcHdrPtr->flags & RPC_CLOSE) {
  729.         /*
  730.          * This is an explicit acknowledgment to our reply.
  731.          * Free the server regardless of its state.  The call-back
  732.          * procedure to free resources will be called the next
  733.          * time the server process gets a request, or by Rpc_Daemon.
  734.          */
  735.         rpcSrvStat.closeAcks++;
  736.         srvPtr->state = SRV_FREE;
  737.         RpcAddServerTrace(srvPtr, (RpcHdr *) NIL, FALSE, 10);
  738.         } else if (rpcHdrPtr->flags & RPC_LASTFRAG) {
  739.         /*
  740.          * This is a partial acknowledgment.  The fragMask field
  741.          * has the summary bitmask of the client which indicates
  742.          * what fragments the client has received.
  743.          */
  744.         rpcSrvStat.recvPartial++;
  745.         srvPtr->fragsDelivered = rpcHdrPtr->fragMask;
  746.         RpcResend(srvPtr);
  747.         } else {
  748.         /*
  749.          * Do nothing. Unknown kind of ack.
  750.          */
  751.         rpcSrvStat.unknownAcks++;
  752.         }
  753.     } else {
  754.         /*
  755.          * Process another fragment or a re-sent request.
  756.          */
  757.         switch(srvPtr->state) {
  758.         default:
  759.             /*
  760.              * oops.  A client is using the same RPC ID that it
  761.              * used with use last (as it crashed, probably).
  762.              * Reset srvPtr->replyRpcHdr.ID so that we can accept
  763.              * new requests from the client.
  764.              */
  765. #ifdef notdef
  766.         printf("Unexpected Server state %x, idx %d, Rpc ID <%x> flags <%x> clientID %d\n",
  767.                 srvPtr->index, srvPtr->state, rpcHdrPtr->ID,
  768.                 rpcHdrPtr->flags, rpcHdrPtr->clientID);
  769. #endif
  770.             rpcSrvStat.badState++;
  771.             srvPtr->replyRpcHdr.ID = 0;
  772.             srvPtr->state = SRV_FREE;
  773.             break;
  774.         case SRV_FREE:
  775.             /*
  776.              * This is an extra packet that has arrived after the
  777.              * client has explicitly acknowledged its reply.
  778.              */
  779.             rpcSrvStat.extra++;
  780.             break;
  781.         case SRV_FRAGMENT:
  782.             /*
  783.              * Sanity check to make sure we expect fragments
  784.              * and then continue fragment reasembly.
  785.              */
  786.             if (rpcHdrPtr->fragMask == 0 ||
  787.             rpcHdrPtr->numFrags == 0) {
  788.             rpcSrvStat.nonFrag++;
  789.             printf("ServerDispatch - got a non-fragment\n");
  790.             break;
  791.             }
  792.             if (srvPtr->fragsReceived & rpcHdrPtr->fragMask) {
  793.             /*
  794.              * Duplicate Fragment.  This ack will return
  795.              * the srvPtr->fragsReceived bitmask to the client.
  796.              */
  797.             rpcSrvStat.dupFrag++;
  798.             RpcAck(srvPtr, RPC_LASTFRAG);
  799.             break;
  800.             } else {
  801.             /*
  802.              * Copy in new fragment and check for completion.
  803.              */
  804.             rpcSrvStat.reassembly++;
  805.             RpcScatter(rpcHdrPtr, &srvPtr->request);
  806.             /*
  807.              * Update actual size information
  808.              */
  809.             size = rpcHdrPtr->paramSize + rpcHdrPtr->paramOffset;
  810.             if (srvPtr->actualParamSize < size) {
  811.                 srvPtr->actualParamSize = size;
  812.             }
  813.             size = rpcHdrPtr->dataSize + rpcHdrPtr->dataOffset;
  814.             if (srvPtr->actualDataSize < size) {
  815.                 srvPtr->actualDataSize = size;
  816.             }
  817.  
  818.             srvPtr->fragsReceived |= rpcHdrPtr->fragMask;
  819.             if (srvPtr->fragsReceived ==
  820.                 rpcCompleteMask[rpcHdrPtr->numFrags]) {
  821.                 srvPtr->state = SRV_BUSY;
  822.                 RpcAddServerTrace(srvPtr, (RpcHdr *) NIL, FALSE, 3);
  823.                 rpcSrvStat.handoffs++;
  824.                 Sync_MasterBroadcast(&srvPtr->waitCondition);
  825.             } else if (rpcHdrPtr->flags & RPC_LASTFRAG) {
  826.                 /*
  827.                  * Incomplete packet after we've gotten
  828.                  * the last fragment in the series.  Partial Ack.
  829.                  */
  830.                 rpcSrvStat.sentPartial++;
  831.                 RpcAck(srvPtr, RPC_LASTFRAG);
  832.             } else {
  833.                 /*
  834.                  * Ignore any "please ack" requests here.  If
  835.                  * the client is resending it will already
  836.                  * trigger a partial ack on every duplicate
  837.                  * fragment we get.
  838.                  */
  839.             }
  840.             }
  841.             break;
  842.         case SRV_BUSY:
  843.             /*
  844.              * We already got this request and the server is busy
  845.              * with it.  We send an explicit acknowledgment to the
  846.              * client to let it know that we successfully got the
  847.              * request.
  848.              */
  849.             rpcSrvStat.busyAcks++;
  850.             RpcAck(srvPtr, 0);
  851.             RpcAddServerTrace(srvPtr, (RpcHdr *) NIL, FALSE, 18);
  852.             break;
  853.         case SRV_WAITING:
  854.             /*
  855.              * The client has dropped our reply, we resend it.
  856.              */
  857.             rpcSrvStat.resends++;
  858.             RpcResend(srvPtr);
  859.             break;
  860.         }
  861.     }
  862. #ifdef TIMESTAMP
  863.     RPC_TRACE(rpcHdrPtr, RPC_SERVER_c, "return");
  864. #endif /* TIMESTAMP */
  865.     }
  866. unlock:
  867.     MASTER_UNLOCK(&srvPtr->mutex);
  868. }
  869.  
  870. /*
  871.  *----------------------------------------------------------------------
  872.  *
  873.  * Rpc_ErrorReply --
  874.  *
  875.  *    Return an error code and an empty reply to a client.
  876.  *
  877.  * Results:
  878.  *    Transmits an error reply to the client host.
  879.  *
  880.  * Side effects:
  881.  *    Send the packet.  Clears the freeReplyProc and Data because
  882.  *    there is an empty reply.
  883.  *
  884.  *----------------------------------------------------------------------
  885.  */
  886. void
  887. Rpc_ErrorReply(srvToken, error)
  888.     ClientData srvToken;        /* Opaque token passed to stub */
  889.     int error;                /* Error code to return to client */
  890. {
  891.     RpcServerState *srvPtr;
  892.     register RpcHdr    *rpcHdrPtr;
  893.     register RpcHdr    *requestHdrPtr;
  894.     char errMsg[1024];
  895.  
  896.     srvPtr = (RpcServerState *)srvToken;
  897.     rpcHdrPtr = &srvPtr->replyRpcHdr;
  898.     requestHdrPtr = &srvPtr->requestRpcHdr;
  899.  
  900.     srvPtr->freeReplyProc = (int (*)())NIL;
  901.     srvPtr->freeReplyData = (ClientData)NIL;
  902.  
  903.     RpcSrvInitHdr(srvPtr, rpcHdrPtr, requestHdrPtr);
  904.  
  905.     /*
  906.      * Communicate the error code back in the command field.  Identify the
  907.      * client if the problem is no disk space, so that someone can put it
  908.      * in the debugger or kill the offending process.
  909.      */
  910.     if (error == FS_NO_DISK_SPACE) {
  911.     sprintf(errMsg,
  912.         "%s: <%s> returning \"no disk space\" to client %d.\n",
  913.         "Rpc_ErrorReply", rpcService[rpcHdrPtr->command].name,
  914.         srvPtr->clientID);
  915.     if (Timer_OkToWhine(errMsg)) {
  916.         printf(errMsg);
  917.     }
  918.     }
  919.     rpcHdrPtr->command = error;
  920.     rpcHdrPtr->flags = RPC_REPLY | RPC_ERROR;
  921.  
  922.     /*
  923.      * Clear sizes in the reply buffers, but not the addresses.
  924.      * This forces a null return and our caller can free the data.
  925.      */
  926.     srvPtr->reply.paramBuffer.length = 0;
  927.     srvPtr->reply.dataBuffer.length = 0;
  928.  
  929.     (void)RpcOutput(rpcHdrPtr->clientID, rpcHdrPtr, &srvPtr->reply,
  930.              (RpcBufferSet *)NIL, 0, (Sync_Semaphore *)NIL);
  931. }
  932.  
  933.  
  934. /*
  935.  *----------------------------------------------------------------------
  936.  *
  937.  * RpcSrvInitHdr --
  938.  *
  939.  *    Initialize the header of a server message from fields
  940.  *    in the clients request message.  This relies on initialization
  941.  *    of unchanging fields inside RpcBufferInit.
  942.  *
  943.  * Results:
  944.  *    None.
  945.  *
  946.  * Side effects:
  947.  *    Addressing and sequencing information from the clients request
  948.  *    message is copeid into the header of a server's outgoing message.
  949.  *
  950.  *----------------------------------------------------------------------
  951.  */
  952. void
  953. RpcSrvInitHdr(srvPtr, rpcHdrPtr, requestHdrPtr)
  954.     RpcServerState    *srvPtr;
  955.     RpcHdr        *rpcHdrPtr;    /* header of outgoing message */
  956.     RpcHdr        *requestHdrPtr;    /* header of client's request */
  957. {
  958.     rpcHdrPtr->serverID = rpc_SpriteID;
  959.     rpcHdrPtr->clientID = requestHdrPtr->clientID;
  960.     rpcHdrPtr->channel = requestHdrPtr->channel;
  961.     rpcHdrPtr->bootID = rpcBootID;
  962.     rpcHdrPtr->ID = requestHdrPtr->ID;
  963.     rpcHdrPtr->numFrags = 0;
  964.     rpcHdrPtr->fragMask = 0;
  965.     rpcHdrPtr->command = requestHdrPtr->command;
  966.     rpcHdrPtr->paramSize = 0;
  967.     rpcHdrPtr->dataSize = 0;
  968.  
  969.     if (srvPtr == (RpcServerState *) NIL) {
  970.     /*
  971.      * If this is a negative ack due to no server proc being available,
  972.      * make sure the serverHint value is reasonable so we don't mess up
  973.      * the client.
  974.      */
  975.     rpcHdrPtr->serverHint = 0;
  976.     }
  977. }
  978.  
  979. /*
  980.  *----------------------------------------------------------------------
  981.  *
  982.  * Rpc_Reply --
  983.  *
  984.  *    Return a reply to a client.
  985.  *
  986.  * Results:
  987.  *    None.
  988.  *
  989.  * Side effects:
  990.  *    Send the reply.
  991.  *
  992.  *----------------------------------------------------------------------
  993.  */
  994. void
  995. Rpc_Reply(srvToken, error, storagePtr, freeReplyProc, freeReplyData)
  996.     ClientData        srvToken;        /* The token for the server
  997.                          * passed to the stub from
  998.                          * the server process */
  999.     int            error;            /* Error code, or SUCCESS */
  1000.     register Rpc_Storage *storagePtr;        /* Only the reply fields are
  1001.                              * significant. */
  1002.     int            (*freeReplyProc) _ARGS_((ClientData freeReplyData));
  1003.                         /* Procedure to call to free
  1004.                          * up reply state, or NIL */
  1005.     ClientData        freeReplyData;        /* Passed to freeReplyProc */
  1006. {
  1007.     RpcServerState    *srvPtr;
  1008.     register RpcHdr    *rpcHdrPtr;
  1009.     register RpcHdr    *requestHdrPtr;
  1010.     char errMsg[1024];
  1011.  
  1012.     srvPtr = (RpcServerState *)srvToken;
  1013.     rpcHdrPtr = &srvPtr->replyRpcHdr;
  1014.     requestHdrPtr = &srvPtr->requestRpcHdr;
  1015.  
  1016.     /*
  1017.      * Set up the call back that will free resources associated
  1018.      * with the reply.
  1019.      */
  1020.     srvPtr->freeReplyProc = freeReplyProc;
  1021.     srvPtr->freeReplyData = freeReplyData;
  1022.     
  1023.     RpcSrvInitHdr(srvPtr, rpcHdrPtr, requestHdrPtr);
  1024.     rpcHdrPtr->flags = RPC_REPLY;
  1025.     if (error) {
  1026.     /*
  1027.      * Communicate the error code back in the command field.  Identify 
  1028.      * the client if the problem is no disk space, so that someone can 
  1029.      * put it in the debugger or kill the offending process.
  1030.      */
  1031.     if (error == FS_NO_DISK_SPACE) {
  1032.         sprintf(errMsg,
  1033.             "%s: <%s> returning \"no disk space\" to client %d.\n",
  1034.             "Rpc_Reply", rpcService[rpcHdrPtr->command].name,
  1035.             srvPtr->clientID);
  1036.         if (Timer_OkToWhine(errMsg)) {
  1037.         printf(errMsg);
  1038.         }
  1039.     }
  1040.     rpcHdrPtr->command = error;
  1041.     rpcHdrPtr->flags |= RPC_ERROR;
  1042.     }
  1043.  
  1044.     /*
  1045.      * Copy buffer pointers into the server's state.
  1046.      */
  1047.     rpcHdrPtr->paramSize = storagePtr->replyParamSize;
  1048.     srvPtr->reply.paramBuffer.length = storagePtr->replyParamSize;
  1049.     srvPtr->reply.paramBuffer.bufAddr = storagePtr->replyParamPtr;
  1050.  
  1051.     rpcHdrPtr->dataSize = storagePtr->replyDataSize;
  1052.     srvPtr->reply.dataBuffer.length = storagePtr->replyDataSize;
  1053.     srvPtr->reply.dataBuffer.bufAddr = storagePtr->replyDataPtr;
  1054.  
  1055.     (void)RpcOutput(rpcHdrPtr->clientID, rpcHdrPtr, &srvPtr->reply,
  1056.              srvPtr->fragment, 0, (Sync_Semaphore *)NIL);
  1057. }
  1058.  
  1059.  
  1060.  
  1061. /*
  1062.  *----------------------------------------------------------------------
  1063.  *
  1064.  * RpcAck --
  1065.  *
  1066.  *    Return an explicit acknowledgment to a client.
  1067.  *
  1068.  * Results:
  1069.  *    None.
  1070.  *
  1071.  * Side effects:
  1072.  *    None.
  1073.  *
  1074.  *----------------------------------------------------------------------
  1075.  */
  1076. void
  1077. RpcAck(srvPtr, flags)
  1078.     RpcServerState *srvPtr;
  1079.     int flags;
  1080. {
  1081.     RpcHdr    *ackHdrPtr;
  1082.     RpcHdr    *requestHdrPtr;
  1083.  
  1084.     ackHdrPtr = &srvPtr->ackRpcHdr;
  1085.     requestHdrPtr = &srvPtr->requestRpcHdr;
  1086.  
  1087.     ackHdrPtr->flags = flags | RPC_ACK;
  1088.     RpcSrvInitHdr(srvPtr, ackHdrPtr, requestHdrPtr);
  1089.     /*
  1090.      * Let the client know what fragments we have received
  1091.      * so it can optimize retransmission.
  1092.      */
  1093.     ackHdrPtr->fragMask = srvPtr->fragsReceived;
  1094.     /*
  1095.      * Note, can't try ARP here because of it's synchronization with
  1096.      * a master lock and because we are called at interrupt time.
  1097.      */
  1098.     (void)RpcOutput(ackHdrPtr->clientID, ackHdrPtr, &srvPtr->ack,
  1099.              (RpcBufferSet *)NIL, 0, (Sync_Semaphore *)NIL);
  1100. }
  1101.  
  1102. /*
  1103.  *----------------------------------------------------------------------
  1104.  *
  1105.  * RpcResend --
  1106.  *
  1107.  *    Resend a reply to a client.
  1108.  *
  1109.  * Results:
  1110.  *    None.
  1111.  *
  1112.  * Side effects:
  1113.  *    Send the reply.
  1114.  *
  1115.  *----------------------------------------------------------------------
  1116.  */
  1117. void
  1118. RpcResend(srvPtr)
  1119.     RpcServerState    *srvPtr;
  1120. {
  1121.     /*
  1122.      * Consistency check against a service stub that forgot to send a reply.
  1123.      * We can't check sequence numbers because RpcServerDispatch updates the
  1124.      * reply sequence number, but we can verify that the command
  1125.      * in the reply matches the command in the reply.
  1126.      */
  1127.     if ((srvPtr->replyRpcHdr.flags & RPC_ERROR) == 0 &&
  1128.     (srvPtr->replyRpcHdr.command != srvPtr->requestRpcHdr.command)) {
  1129.     printf("RpcResend: RPC %d, client %d, RPC seq # %x, forgot reply?\n",
  1130.         srvPtr->requestRpcHdr.command, srvPtr->requestRpcHdr.clientID,
  1131.         srvPtr->requestRpcHdr.ID);
  1132.     return;
  1133.     }
  1134.     (void)RpcOutput(srvPtr->replyRpcHdr.clientID, &srvPtr->replyRpcHdr,
  1135.                &srvPtr->reply, srvPtr->fragment,
  1136.                srvPtr->fragsDelivered, (Sync_Semaphore *)NIL);
  1137. }
  1138.  
  1139. /*
  1140.  *----------------------------------------------------------------------
  1141.  *
  1142.  * RpcProbe --
  1143.  *
  1144.  *    Send a probe message to the client to see if it is still interested
  1145.  *    in the connection.  The Ack message header/buffer is used for this.
  1146.  *    Synchronization note.  We are called with the srvPtr mutex locked,
  1147.  *    but the server process is not marked BUSY so the dispatcher might
  1148.  *    try to allocate this server.  The mutex prevents this, but it
  1149.  *    is important to not pass the mutex to RpcOutput, which would use
  1150.  *    it to wait for output of the packet.  In that case the mutex is
  1151.  *    released for a while, leaving a window of vulnerability where the
  1152.  *    server could get allocated and the mutex grabbed by the dispatcher.
  1153.  *    By not passing the mutex the packet is sent asynchronously, so there
  1154.  *    is a very remote chance we could try to issue another probe while
  1155.  *    this is still in the output queue.  However, we would be sending
  1156.  *    the same information in the packet, so there shouldn't be a problem.
  1157.  *
  1158.  * Results:
  1159.  *    None.
  1160.  *
  1161.  * Side effects:
  1162.  *    Send the probe message.
  1163.  *
  1164.  *----------------------------------------------------------------------
  1165.  */
  1166. void
  1167. RpcProbe(srvPtr)
  1168.     RpcServerState    *srvPtr;
  1169. {
  1170.     RpcHdr    *ackHdrPtr;
  1171.     RpcHdr    *requestHdrPtr;
  1172.  
  1173.     ackHdrPtr = &srvPtr->ackRpcHdr;
  1174.     requestHdrPtr = &srvPtr->requestRpcHdr;
  1175.  
  1176.     ackHdrPtr->flags = RPC_ACK | RPC_CLOSE;
  1177.     RpcSrvInitHdr(srvPtr, ackHdrPtr, requestHdrPtr);
  1178.  
  1179.     (void)RpcOutput(ackHdrPtr->clientID, ackHdrPtr, &srvPtr->ack,
  1180.              (RpcBufferSet *)NIL, 0, (Sync_Semaphore *)NIL);
  1181. }
  1182.  
  1183.  
  1184. /*
  1185.  *----------------------------------------------------------------------
  1186.  *
  1187.  * RpcAddServerTrace --
  1188.  *
  1189.  *    Add another trace to the list of state tracing for rpc servers.
  1190.  *
  1191.  * Results:
  1192.  *    None.
  1193.  *
  1194.  * Side effects:
  1195.  *    The list is lengthened.
  1196.  *
  1197.  *----------------------------------------------------------------------
  1198.  */
  1199. void
  1200. RpcAddServerTrace(srvPtr, rpcHdrPtr, noneThere, num)
  1201.     RpcServerState    *srvPtr;    /* State to record */
  1202.     RpcHdr         *rpcHdrPtr;    /* The request message header */
  1203.     Boolean        noneThere;    /* No server free */
  1204.     int            num;        /* Which trace */
  1205. {
  1206.     RpcServerStateInfo    *rpcTracePtr;
  1207.  
  1208.     if (!rpcServerTraces.okay) {
  1209.     return;
  1210.     }
  1211.     rpcTracePtr = &(rpcServerTraces.traces[rpcServerTraces.traceIndex]);
  1212.     (void) bzero((Address) rpcTracePtr, sizeof (RpcServerStateInfo));
  1213.     if (!noneThere) {
  1214.     rpcTracePtr->index = srvPtr->index;
  1215.     rpcTracePtr->clientID = srvPtr->clientID;
  1216.     rpcTracePtr->channel = srvPtr->channel;
  1217.     rpcTracePtr->state = srvPtr->state;
  1218.     } else {
  1219.     rpcTracePtr->index = -1;
  1220.     rpcTracePtr->clientID = rpcHdrPtr->clientID;
  1221.     rpcTracePtr->channel = rpcHdrPtr->channel;
  1222.     rpcTracePtr->state = rpcHdrPtr->command;
  1223.     }
  1224.     rpcTracePtr->num = num;
  1225.     Timer_GetCurrentTicks(&rpcTracePtr->time);
  1226.     rpcServerTraces.traceIndex++;
  1227.     if (rpcServerTraces.traceIndex >= RPC_NUM_TRACES) {
  1228.     rpcServerTraces.okay = FALSE;
  1229.     rpcServerTraces.error = TRUE;
  1230.     }
  1231.  
  1232.     return;
  1233. }
  1234.  
  1235.  
  1236. /*
  1237.  *----------------------------------------------------------------------
  1238.  *
  1239.  * Rpc_OkayToTrace --
  1240.  *
  1241.  *    Okay to turn on rpc server state tracing.
  1242.  *
  1243.  * Results:
  1244.  *    None.
  1245.  *
  1246.  * Side effects:
  1247.  *    The tracing is turned on.
  1248.  *
  1249.  *----------------------------------------------------------------------
  1250.  */
  1251. ENTRY void
  1252. Rpc_OkayToTrace(okay)
  1253.     Boolean    okay;
  1254. {
  1255.     MASTER_LOCK(&(rpcServerTraces.mutex));
  1256.     if (okay) {
  1257.     if (!rpcServerTraces.error) {
  1258.         rpcServerTraces.okay = okay;
  1259.     }
  1260.     } else {
  1261.     rpcServerTraces.okay = okay;
  1262.     }
  1263.     MASTER_UNLOCK(&(rpcServerTraces.mutex));
  1264.  
  1265.     return;
  1266. }
  1267.  
  1268.  
  1269. /*
  1270.  *----------------------------------------------------------------------
  1271.  *
  1272.  * Rpc_FreeTraces --
  1273.  *
  1274.  *    If memory allocation is involved, free up the space used by the rpc
  1275.  *    server tracing.  Otherwise, just reinitialize it.
  1276.  *
  1277.  * Results:
  1278.  *    None.
  1279.  *
  1280.  * Side effects:
  1281.  *    Tracing is turned off and some reinitialization is done.
  1282.  *
  1283.  *----------------------------------------------------------------------
  1284.  */
  1285. ENTRY void
  1286. Rpc_FreeTraces()
  1287. {
  1288.     MASTER_LOCK(&(rpcServerTraces.mutex));
  1289.     rpcServerTraces.okay = FALSE;
  1290.  
  1291.     rpcServerTraces.traceIndex = 0;
  1292.     rpcServerTraces.error = FALSE;
  1293.  
  1294.     MASTER_UNLOCK(&(rpcServerTraces.mutex));
  1295.     return;
  1296. }
  1297.  
  1298.  
  1299. /*
  1300.  *----------------------------------------------------------------------
  1301.  *
  1302.  * Rpc_DumpServerTraces --
  1303.  *
  1304.  *    Dump the server traces into a buffer for the user.
  1305.  *
  1306.  * Results:
  1307.  *    Failure if something goes wrong.  Success otherwise.
  1308.  *
  1309.  * Side effects:
  1310.  *    The trace info is copied into a buffer.  Size of needed buffer is
  1311.  *    also copied out.
  1312.  *
  1313.  *----------------------------------------------------------------------
  1314.  */
  1315. ENTRY ReturnStatus
  1316. Rpc_DumpServerTraces(length, resultPtr, lengthNeededPtr)
  1317.     int                     length;         /* size of data buffer */
  1318.     RpcServerUserStateInfo    *resultPtr;    /* Array of info structs. */
  1319.     int                     *lengthNeededPtr;/* to return space needed */
  1320.  
  1321. {
  1322.     RpcServerUserStateInfo    *infoPtr;
  1323.     RpcServerStateInfo        *itemPtr;
  1324.     int                numNeeded;
  1325.     int                numAvail;
  1326.     int                i;
  1327.  
  1328.     MASTER_LOCK(&(rpcServerTraces.mutex));
  1329.     if (rpcServerTraces.traceIndex <= 0) {
  1330.     MASTER_UNLOCK(&(rpcServerTraces.mutex));
  1331.     return FAILURE;
  1332.     }
  1333.     if (resultPtr != (RpcServerUserStateInfo *) NIL) {
  1334.     bzero((char *) resultPtr, length);
  1335.     }
  1336.     numNeeded = 0;
  1337.     numAvail = length / sizeof (RpcServerUserStateInfo);
  1338.  
  1339.     infoPtr = resultPtr;
  1340.     for (i = 0; i < rpcServerTraces.traceIndex; i++) {
  1341.     itemPtr = &(rpcServerTraces.traces[i]);
  1342.     numNeeded++;
  1343.     if (numNeeded > numAvail) {
  1344.         continue;
  1345.     }
  1346.     infoPtr->index = itemPtr->index;
  1347.     infoPtr->clientID = itemPtr->clientID;
  1348.     infoPtr->channel = itemPtr->channel;
  1349.     infoPtr->state = itemPtr->state;
  1350.     infoPtr->num = itemPtr->num;
  1351.     Timer_GetRealTimeFromTicks(itemPtr->time, &(infoPtr->time), 
  1352.                 (int *) NIL, (Boolean *) NIL);
  1353.     infoPtr++;
  1354.     }
  1355.     *lengthNeededPtr = numNeeded * sizeof (RpcServerUserStateInfo);
  1356.  
  1357.     MASTER_UNLOCK(&(rpcServerTraces.mutex));
  1358.     return SUCCESS;
  1359. }
  1360.  
  1361. void
  1362. RpcInitServerTraces()
  1363. {
  1364.     rpcServerTraces.traces = (RpcServerStateInfo *) malloc(RPC_NUM_TRACES *
  1365.                         sizeof (RpcServerStateInfo));
  1366.     return;
  1367. }
  1368.  
  1369.  
  1370.  
  1371. /*
  1372.  *----------------------------------------------------------------------
  1373.  *
  1374.  * RpcSetNackBufs --
  1375.  *
  1376.  *    Allocate and set up the correct number of nack buffers.
  1377.  *
  1378.  * Results:
  1379.  *    None.
  1380.  *
  1381.  * Side effects:
  1382.  *    Some freeing and malloc'ing.
  1383.  *
  1384.  *----------------------------------------------------------------------
  1385.  */
  1386. void
  1387. RpcSetNackBufs()
  1388. {
  1389.     int    i;
  1390.  
  1391.     if (oldNumNackBuffers == rpc_NumNackBuffers) {
  1392.     /* Nothing to do, initialized already. */
  1393.     return;
  1394.     }
  1395.     if (rpcServiceEnabled) {
  1396.     /* Cannot change nack buffers once service is enabled, for now. */
  1397.     return;
  1398.     }
  1399.     /* Free old nack buffers if there were any. */
  1400.     if (oldNumNackBuffers > 0 && rpcNack.rpcHdrArray != (RpcHdr *) NIL) {
  1401.     free((char *) rpcNack.rpcHdrArray);
  1402.     free((char *) rpcNack.hdrState);
  1403.     free((char *) rpcNack.bufferSet);
  1404.     /*
  1405.      * Note, this won't free up all the buffer stuff since
  1406.      * RpcBufferInit calls Vm_RawAlloc instead of malloc.
  1407.      */
  1408.     }
  1409.     /* Allocate new nack buffers. */
  1410.     rpcNack.rpcHdrArray = (RpcHdr *) malloc(rpc_NumNackBuffers *
  1411.         sizeof (RpcHdr));
  1412.     rpcNack.hdrState = (int *) malloc(rpc_NumNackBuffers * sizeof (int));
  1413.  
  1414.     rpcNack.bufferSet = (RpcBufferSet *) malloc(rpc_NumNackBuffers *
  1415.             sizeof (RpcBufferSet));
  1416.  
  1417.     for (i = 0; i < rpc_NumNackBuffers; i++) {
  1418.         rpcNack.hdrState[i] = RPC_NACK_FREE;
  1419.         RpcBufferInit(&(rpcNack.rpcHdrArray[i]),
  1420.                 &(rpcNack.bufferSet[i]), -1, -1);
  1421.     }
  1422.     /* set old to new */
  1423.     rpcNack.numFree = rpc_NumNackBuffers;
  1424.     oldNumNackBuffers = rpc_NumNackBuffers;
  1425.  
  1426.     return;
  1427. }
  1428.